#include "stdafx.h"
#include "OgreGpuCommandBufferFlush.h"
#include <parseScene.h>
#include <baloon.h>
#include <bird.h>
#include <DefaultObjectContactCallback.h>
#include "Gorilla.h"
#include "mainMenu.h"
#include "PagedGeometry.h"
#include "BatchPage.h"
#include "ImpostorPage.h"
#include "TreeLoader3D.h"
#include "GrassLoader.h"
#include "lvl_update.h"
#include "levels.h"


using namespace Ogre;

class MainListener : public FrameListener, public OIS::MouseListener, public OIS::KeyListener
{
public:
	MainListener(OIS::Keyboard *keyboard, OIS::Mouse *mouse,SceneManager * sceneMgr,OgreNewt::World* W, Ogre::Root *mRoot,Ogre::RenderWindow* mWin)
       
    {
/*
		W->setMinimumFrameRate(30);
		W->setThreadCount(2);
		W->setUpdateFPS(60,1);
		W->setMultithreadSolverOnSingleIsland(1);
		W->setPlatformArchitecture(2);
		W->setFrictionModel(1);
		W->setSolverModel(1);
*/
		
		mBufferFlush.start(1);

		count=0;

		mSceneMgr=sceneMgr;
		mWindow=mWin;
		engine = irrklang::createIrrKlangDevice();
		engine->setListenerPosition(irrklang::vec3df(0,0,0), irrklang::vec3df(0,0,1));
		//engine->play2D("../../media/Afterglow.ogg",true);

		mWorld=W;
		mWorld->setSolverModel(3);
		mCamera=mSceneMgr->getCamera("Camera");
		mKeyboard=keyboard;
		mMouse=mouse;
		 if (mMouse)
            mMouse->setEventCallback(this);
		 if (mKeyboard)
            mKeyboard->setEventCallback(this);

		env=new EnvironmentSounds(engine);
		SceneNode* n=mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,0,0));
		
		stoji_mat = new OgreNewt::MaterialID(mWorld);
		ide_mat = new OgreNewt::MaterialID(mWorld);
		flag_mat = new OgreNewt::MaterialID(mWorld);
		grab_mat = new OgreNewt::MaterialID(mWorld);


		 OgreNewt::MaterialPair* material_pair = new OgreNewt::MaterialPair( mWorld, ide_mat, mWorld->getDefaultMaterialID() );
		 material_pair->setDefaultFriction(0.0, 0.0f);
		 material_pair->setDefaultElasticity(0);
		 material_pair->setDefaultSurfaceThickness(0.01);
		
		 material_pair = new OgreNewt::MaterialPair( mWorld, ide_mat, grab_mat );
		 material_pair->setDefaultCollidable(0);

		 material_pair = new OgreNewt::MaterialPair( mWorld, stoji_mat, grab_mat );
		 material_pair->setDefaultCollidable(0);

		 material_pair = new OgreNewt::MaterialPair( mWorld, ide_mat, flag_mat );
		 material_pair->setDefaultCollidable(0);
		
		 material_pair = new OgreNewt::MaterialPair( mWorld, stoji_mat, flag_mat );
		 material_pair->setDefaultCollidable(0);

		 material_pair = new OgreNewt::MaterialPair( mWorld, mWorld->getDefaultMaterialID() , flag_mat );
		 material_pair->setDefaultCollidable(0);

		 material_pair = new OgreNewt::MaterialPair( mWorld, flag_mat , flag_mat );
		 material_pair->setDefaultCollidable(0);

		 OgreNewt::MaterialPair* material_pair2 = new OgreNewt::MaterialPair( mWorld, stoji_mat, mWorld->getDefaultMaterialID() );
		 material_pair2->setDefaultFriction(4.0, 4.0f);
		 material_pair2->setDefaultElasticity(0);

		 DefaultObjectContactCallback* callb=new DefaultObjectContactCallback(engine);
		 material_pair2 = new OgreNewt::MaterialPair( mWorld,  mWorld->getDefaultMaterialID(), mWorld->getDefaultMaterialID() );
		 material_pair2->setDefaultFriction(0.8, 0.8f);
		 material_pair2->setDefaultSoftness(0.1);
		 material_pair2->setDefaultElasticity(0.1);
		// material_pair2->setContactCallback(callb);

		
		myMenu=new mainMenu(mSceneMgr,mCamera,mWindow,mRoot->getRenderSystem(),engine);
		myMenu->setMainMenu();
		gameState=MENU;
		lvlUpdate=NULL;

		//p= new Player(mSceneMgr,mWorld,stoji_mat,ide_mat,flag_mat,engine);
		//createLevel2(mSceneMgr,mWorld,flag_mat,&lvlUpdate,p);	
		createMenuLevel(mSceneMgr,mWorld,flag_mat,&lvlUpdate);

    }

	void default_callback(OgreNewt::Body* me, float timeStep, int threadIndex )
	{
	me->addForce(Vector3(0,-6,0));
	}

    bool frameStarted(const FrameEvent& evt)
    {
		lvlUpdate->updateLvl(evt.timeSinceLastFrame);
		updateGodRays();
		updateHurtEffect(evt.timeSinceLastFrame*2.5);

		mKeyboard->capture();
		mMouse->capture();

		if(gameState==MENU)
			myMenu->updateMenu(evt.timeSinceLastFrame);
		else
		if(gameState==PLAY)
		{	
			myMenu->updateFPS(p->getParam().y);
			p->update(evt.timeSinceLastFrame);
			Vector3 pos=p->getBody()->getOgreNode()->getPosition();
			Vector3 or=mCamera->getDerivedOrientation()*Vector3(0,0,1);
			//Ogre::LogManager::getSingleton().getDefaultLog()->logMessage(Ogre::StringConverter::toString(pos),Ogre::LML_NORMAL);
			engine->setListenerPosition(irrklang::vec3df(pos.x,pos.y,pos.z), irrklang::vec3df(or.x,or.y,or.z));
			env->update(pos);
		}

		return cont;
    }

	virtual bool keyPressed(const OIS::KeyEvent &arg) { 
		
		if(gameState==PLAY)
		p->pressedKey(arg);

		if(gameState==MENU)
		{
			int a=myMenu->pressedKey(arg);
			if(a==1) cont=false;
		}

		switch (arg.key)
		{
			   case OIS::KC_M: 
				   {
						makecube();
				   }
			   break;

		   case OIS::KC_ESCAPE:
			   cont=false;
			   break;
		/*
           case OIS::KC_TAB: 
			   if(gameState==PLAY) 
			   {gameState=PAUSE;
			    p->stopMoving();
			    makePauseMenu();
				mousePointer->yes_background(1);
			   }
			   else
			   if(gameState==PAUSE) 
			   {gameState=PLAY;
			   mLayer->hide();
			   myCaptions.clear();
			   mLayer->destroyAllCaptions();
			   mLayer->destroyAllRectangles();
			   mousePointer->no_background();
			   }
			   break;*/

           default:
              break;
		}
		 return true;	}

    virtual bool keyReleased(const OIS::KeyEvent &arg) { 
		
		if(gameState==PLAY)
		p->releasedKey(arg);

		return true; }

	virtual bool mouseMoved(const OIS::MouseEvent &e) { 

		if(gameState==MENU)
		myMenu->mouseMoveUpdate(e.state.X.rel,e.state.Y.rel);
		if(gameState==PLAY)
		p->movedMouse(e);
	
		return true; }

    virtual bool mousePressed(const OIS::MouseEvent &arg, OIS::MouseButtonID id) { 

		if(gameState==PLAY)
		p->pressedMouse(arg,id);
		else
		if(gameState==MENU)
		{
		int i=myMenu->mainMenuPressed();
		if(i==1)
			{	
			gameState=PLAY;
			mWorld->destroyAllBodies();
			mSceneMgr->clearScene();
			createLevel2(mSceneMgr,mWorld,env,flag_mat,&lvlUpdate);
			p= new Player(mSceneMgr,mWorld,stoji_mat,ide_mat,grab_mat,flag_mat,engine);
			p->setPremenne(&hurtEffect,&ivp,&pvp);
			}
		if(i==3)
			cont=false;
		}
		//else
		//if(gameState==PAUSE)
		//pauseMenuPressed();

		return true; }

    virtual bool mouseReleased(const OIS::MouseEvent &arg, OIS::MouseButtonID id) { 

		if(gameState==PLAY)
		p->releasedMouse(arg,id);

		return true; }

    void updateGodRays()
	{
		
		Vector3 sunPosition = Vector3(50000, -30000, -40000);
		Vector3 worldViewPosition = mCamera->getViewMatrix() * sunPosition;
		Vector3 hcsPosition = mCamera->getProjectionMatrix() * worldViewPosition;
		Vector2 sunScreenSpacePosition = Vector2(0.5f + (0.5f * hcsPosition.x), 0.5f + (0.5f * -hcsPosition.y));
		postProcessListener->SunScreenSpacePosition = Vector4(sunScreenSpacePosition.x, sunScreenSpacePosition.y, 0, 1);
		Ogre::Real par=(mCamera->getDerivedPosition() - (Vector3(300, 300, 400) * Vector3(-400, 300, 400))).dotProduct(mCamera->getDerivedDirection());
		if (par > -50000)
		du=0.0; else 
		du=(-(par/1000000))*3.5;
	}

	void updateHurtEffect(Ogre::Real value)
	{
		if(hurtEffect>0)
		{
		hurtEffect-=value;
		if(hurtEffect<0) hurtEffect=0;
		}
	}

	void makecube()
	{
		Ogre::Vector3 size( 2, 2,2 );
		Ogre::Real mass = 0.3;
		Entity* ent;
		SceneNode* node;
		Ogre::String name;

		name = "Bodyd "+Ogre::StringConverter::toString( count++ );

		ent = mSceneMgr->createEntity( name, "boxEL.mesh" );
		node = mSceneMgr->getRootSceneNode()->createChildSceneNode( name );
		node->attachObject( ent );
		node->setScale( size );
		ent->setCastShadows(true);
		ent->setMaterialName( "murbob" );
		OgreNewt::ConvexCollisionPtr col = OgreNewt::ConvexCollisionPtr(new OgreNewt::CollisionPrimitives::Box( mWorld, size, 0 ));
		OgreNewt::Body* body = new OgreNewt::Body( mWorld, col );

		Ogre::Vector3 inertia, offset;
		col->calculateInertialMatrix(inertia, offset);

		#ifdef OGRENEWT_NO_COLLISION_SHAREDPTR
			delete col;
		#endif

		body->setMassMatrix( mass, mass*inertia );
		body->setCenterOfMass(offset);
		body->attachNode( node );
		body->setType(3);
		body->setCustomForceAndTorqueCallback<MainListener>(&MainListener::default_callback, this);
		body->setPositionOrientation( p->getBody()->getPosition()+Vector3(0,5,0), Ogre::Quaternion::IDENTITY );
//0-default,3-grab,6?5-climb,1-??,2-pullup,4-baloon
	}


private:
    OIS::Keyboard *mKeyboard;
	OIS::Mouse *mMouse;
	irrklang::ISoundEngine* engine; 
	SceneManager * mSceneMgr;
	Camera* mCamera;
	int count;
	OgreNewt::World* mWorld;
	Player* p;
	EnvironmentSounds* env;
	Ogre::GpuCommandBufferFlush mBufferFlush;
	OgreNewt::MaterialID* stoji_mat, *ide_mat, *flag_mat,*grab_mat;
	Ogre::RenderWindow* mWindow;
	mainMenu* myMenu;
OgreNewt::Body* vytah;

LvlUpdate* lvlUpdate;
};





/*

	void vcallback(OgreNewt::Body* me, float timeStep, int threadIndex )
	{
	Real h=me->getPosition().y;
	if(h>40) {h=40; me->setVelocity(Vector3(0,0,0));}
	Real force=(40-h)/1;
	me->addForce(Vector3(0,force,0));
	}

	void vcallback2(OgreNewt::Body* me, float timeStep, int threadIndex )
	{
	me->setVelocity(Vector3(0,vytah->getVelocity().y*-1,0));
	}

		Entity* ent = mSceneMgr->createEntity( "vytahmesh", "vytah.mesh" );
		OgreNewt::ConvexCollisionPtr col = OgreNewt::ConvexCollisionPtr(new OgreNewt::CollisionPrimitives::ConvexHull(mWorld,ent,1));
	
	vytah = new OgreNewt::Body( mWorld, col );

	SceneNode* vnode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
	vnode->attachObject( ent );

	Vector3 inertia, offset;
    col->calculateInertialMatrix(inertia, offset);
#ifdef OGRENEWT_NO_COLLISION_SHAREDPTR
			//no longer need the collision shape object
			delete col;
#endif
			vytah->setMassMatrix( 4, inertia );
            vytah->setCenterOfMass(offset);
			vytah->setCustomForceAndTorqueCallback<MainListener>(&MainListener::vcallback, this);
			//pbody->setContinuousCollisionMode(1);
			vytah->setPositionOrientation( Ogre::Vector3(0.0,40,0.0), Ogre::Quaternion::IDENTITY );
			//vytah->setLinearDamping(0.1);
			vytah->attachNode( vnode );
			OgreNewt::UpVector* uv= new OgreNewt::UpVector(vytah, Vector3::UNIT_Y);
	OgreNewt::UpVector* uv2= new OgreNewt::UpVector(vytah, Vector3::UNIT_Z);
    

	ent = mSceneMgr->createEntity( "vytahmesh2", "vytah.mesh" );
		col = OgreNewt::ConvexCollisionPtr(new OgreNewt::CollisionPrimitives::ConvexHull(mWorld,ent,1));
	
	OgreNewt::Body* vytah2 = new OgreNewt::Body( mWorld, col );

	SceneNode* vnode2 = mSceneMgr->getRootSceneNode()->createChildSceneNode();
	vnode2->attachObject( ent );

    col->calculateInertialMatrix(inertia, offset);
#ifdef OGRENEWT_NO_COLLISION_SHAREDPTR
			//no longer need the collision shape object
			delete col;
#endif
			vytah2->setMassMatrix( 4, inertia );
            vytah2->setCenterOfMass(offset);
			vytah2->setCustomForceAndTorqueCallback<MainListener>(&MainListener::vcallback2, this);
			//pbody->setContinuousCollisionMode(1);
			vytah2->setPositionOrientation( Ogre::Vector3(10.0,0.0,0.0), Ogre::Quaternion::IDENTITY );
			//vytah->setLinearDamping(0.1);
			vytah2->attachNode( vnode2 );
			OgreNewt::UpVector* uv12= new OgreNewt::UpVector(vytah2, Vector3::UNIT_Y);
	OgreNewt::UpVector* uv22= new OgreNewt::UpVector(vytah2, Vector3::UNIT_Z);
*/